#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;
#include<assert.h>
#include<list>
#include<vector>


namespace xlf
{
	class string
	{
	public:
		typedef char* iterator;
		iterator begin()
		{
			return _str;
		}
		iterator end()
		{
			return _str + _size;
		}

		typedef const char* const_iterator;
		const_iterator begin() const
		{
			return _str;
		}

		const_iterator end() const
		{
			return _str + _size;
		}

		string(const char* str = "")
			:_size(strlen(str))
			, _capacity(_size)
		{
			cout << "string(char* str)" << endl;
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}

		string(size_t n, char ch = '\0')
		{
			reserve(n);
			for (size_t i = 0; i < n; i++)
			{
				_str[i] = ch;
			}
			_size = n;
			_str[_size] = ch;
		}

		// s1.swap(s2)
		void swap(string& s)
		{
			::swap(_str, s._str);
			::swap(_size, s._size);
			::swap(_capacity, s._capacity);
		}

		// 拷贝构造
		// s2(s1)
		//左值拷贝/右值拷贝
		//要开空间拷贝数据
		string(const string& s)
			:_str(nullptr)
		{
			cout << "string(const string& s) -- 深拷贝" << endl;

			reserve(s._capacity);
			for (auto ch : s)
			{
				push_back(ch);
			}
		}


		// 移动构造
		// 临时创建的对象，不能取地址，用完就要消亡
		// 深拷贝的类，移动构造才有意义
		//右值拷贝
		//右值通常是一些字面常量、表达式返回值、匿名对象、临时空间存储
		//纯右值：内置类型右值（常量10、整型a+b）
		//将亡值：类类型内置的右值（匿名对象、类型转换中间产生的临时对象）
		string(string&& s)
		{
			cout << "string(string&& s) -- 移动拷贝" << endl;
			swap(s);
			//抢占资源
		}

		// 赋值重载
		string& operator=(const string& s)
		{
			cout << "string& operator=(const string& s) -- 深拷贝" << endl;
			if (this != &s)
			{
				_str[0] = '\0';
				_size = 0;

				reserve(s._capacity);
				for (auto ch : s)
				{
					push_back(ch);
				}
			}

			return *this;
		}

		// 移动赋值
		string& operator=(string&& s)
		{
			cout << "string& operator=(string&& s) -- 移动拷贝" << endl;

			swap(s);
			return *this;
		}

		~string()
		{
			delete[] _str;
			_str = nullptr;
		}

		char& operator[](size_t pos)
		{
			assert(pos < _size);
			return _str[pos];
		}

		void reserve(size_t n)
		{
			if (n > _capacity)
			{
				char* tmp = new char[n + 1];
				if (_str)
				{
					strcpy(tmp, _str);
					delete[] _str;
				}
				_str = tmp;
				_capacity = n;
			}
		}

		void push_back(char ch)
		{
			if (_size >= _capacity)
			{
				size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
				reserve(newcapacity);
			}

			_str[_size] = ch;
			++_size;
			_str[_size] = '\0';
		}

		//string operator+=(char ch)
		string& operator+=(char ch)
		{
			push_back(ch);
			return *this;
		}

		const char* c_str() const
		{
			return _str;
		}
	private:
		char* _str = nullptr;
		size_t _size = 0;
		size_t _capacity = 0; // 不包含最后做标识的\0
	};

	xlf::string to_string(int value)
	{
		bool flag = true;
		if (value < 0)
		{
			flag = false;
			value = 0 - value;
		}
		xlf::string str;

		while (value > 0)
		{
			int x = value % 10;
			value /= 10;
			str += ('0' + x);
		}

		if (flag == false)
		{
			str += '-';
		}

		std::reverse(str.begin(), str.end());

		return str;
	}
}


//////////////////////////////////////////////////////////////////////////

////在函数模板中
//// && && -> &&
//// &  && -> &
//template<class T>
//void func(T&& x)//万能引用/引用折叠
//{
//
//}

void Fun(int& x) {cout << "左值引用" << endl;}

void Fun(const int& x) { cout << "const 左值引用" << endl; }

//std::forward 完美转发在传参的过程中保留对象原生类型属性

void Fun(int&& x) {cout << "右值引用" << endl;}

void Fun(const int&& x) { cout << "const 右值引用" << endl;}

// 模板中的&&不代表右值引用，而是万能引用，其既能接收左值又能接收右值。
// 模板的万能引用只是提供了能够接收同时接收左值引用和右值引用的能力，
// 但是引用类型的唯一作用就是限制了接收的类型，后续使用中都退化成了左值，
// 我们希望能够在传递过程中保持它的左值或者右值的属性, 就需要用我们下面学习的完美转发
template<typename T>
void PerfectForward(T&& t)// T&& -> 传什么T&&就替换成什么
{
	//模板实例化是左值引用，保持属性直接传给Fun
	//模板实例化是右值引用，右值引用属性会退化成左值，转换成右值属性再传给Fun
	//Fun(t);//所以不能直接传
	
	//完美转发:保持属性进行传递
	Fun(forward<T>(t));//类模板
	//在传参的过程中保持了t的原生类型属性
	//完美转发的内部要识别是左值/右值引用
	//如果是左值引用就不用管了，如果是右值引用对象就要move（强制转换）一下
}

////void PerfectForward(int& t)
////{
////	Fun(t);
////}
////
////void PerfectForward(int&& t)
////{
////	Fun(move(t));
////}
////
////void PerfectForward(const int& t)
////{
////	Fun(t);
////}
////
////void PerfectForward(const int&& t)
////{
////	Fun(move(t));
////}

//int main()
//{
//	PerfectForward(10);// 右值
//
//	int a;
//	PerfectForward(a); // 左值
//
//	PerfectForward(std::move(a)); // 右值
//
//	const int b = 8;
//	PerfectForward(b);// const 左值
//
//	PerfectForward(std::move(b)); // const 右值
//
//	return 0;
//}

//void Fun(int& x) 
//{
//	cout << "左值引用" << endl;
//}
//
//void Fun(const int& x) 
//{ 
//	cout << "const 左值引用" << endl;
//}
//
//void Fun(int&& x) 
//{ 
//	cout << "右值引用" << endl;
//}
//
//void Fun(const int&& x) 
//{
//	cout << "const 右值引用" << endl;
//}


// 以下代码在vs2013中不能体现，在vs2019下才能演示体现上面的特性。
//class Person
//{
//public:
//	Person(const char* name = "1111111", int age = 0)
//		:_name(name)
//		, _age(age)
//	{}
//
//	//自动生成拷贝构造和移动构造
//
//
//	//Person(Person&& p) = default;//右值
//	//Person(const Person& p) = default;//左值
//
//	//Person& operator=(Person&& p) = default;//右值
//	//Person& operator=(const Person& p) = default;//左值
//
//	//写了析构就不生成移动构造了
//	//默认生成移动构造的条件：
//	//没有自己实现移动构造函数，且没有实现析构函数、拷贝构造、拷贝赋值重载
//	//中的任意一个
//	/*~Person()
//	{
//
//	}*/
//
//	//析构、拷贝构造、赋值重载在真实的类里面是一体化的，即
//	//需要显式写析构，说明有资源需要释放
//	// 1、说明需要显式写拷贝构造和赋值重载
//	// 2、说明需要显式写移动构造和移动赋值
//	// 
//
//private:
//	xlf::string _name;//（Person自身没有资源要管理，自己的自定义类型的成员有资源管理的需求）
//	                  //在这个场景下，自动生成移动构造是为了自定义类型准备的
//	                  //如果在自定义类型里面没有自动生成移动构造，就会调用拷贝构造，效率就会变低
//	int _age;
//};
//
////自动生成移动构造，对于Data这样的类，其实没啥意义和拷贝构造的功能是一样的
////自动生成移动构造，对于Person这样的类是很有意义的，
////因为Person是右值时，它内部的string也是右值，string就可以走移动构造，效率就提高了
//
//int main()
//{
//	Person s1;//拷贝构造
//	Person s2 = s1;//深拷贝
//	Person s3 = std::move(s1);//移动构造（抢占s1的资源）
//
//	Person s4;
//	s4 = std::move(s2);//移动赋值
//
//	return 0;
//}


//class Person
//{
//public:
//	Person(const char* name = "1111111", int age = 0)
//		:_name(name)
//		, _age(age)
//	{}
//
////	//自动生成拷贝构造和移动构造
////
////	//只声明不实现，声明为私有
////	//C++98
////private:
////	Person(const Person& p);
////	Person(const Person& p);
//
//	Person(const Person& p) = default;
//	Person(const Person& p) = default;
//
//	~Person()
//	{}
//
//private:
//	xlf::string _name;
//	int _age;
//};
//
////Person::Person(const Person& p)
////{}
//
//int main()
//{
//	Person s1;
//	Person s2 = s1;
//	Person s3 = std::move(s1);
//
//	Person s4;
//	s4 = std::move(s2);
//	return 0;
//}

////////////////////////////////////////////////////////////
//可变模板参数
//参数类型可变
//参数个数可变
//template<class ...Args>
//void ShowList(Args... args)
//{
//	//可变参数模板编译时解析
//	cout << sizeof...(args) << endl;
//	//下面运行获取和解析，所以不支持这样用
//	for (size_t i = 0; i < sizeof...(args); i++)
//	{
//		cout << args[i] << " ";
//	}
//	cout << endl;
//}


//参数匹配
//写无参的
void Print()
{
	cout << endl;
}

template<class T,class ...Args>
void Print(T&& x, Args&&... args)
{
	cout << x << " ";
	Print(args...);//递归
	// 当args...参数为0时，就调用无参，就结束递归

	//运行时才判断，所以 sizeof...(args) == 0 就到不到结束条件
	// 编译时递归不能解决
	//if (sizeof...(args) == 0)//递归结束条件？ （错）
	//	return;
}

//编译时递归推到解析参数
template<class ...Args>
void ShowList(Args&&... args)
{
	Print(args...);
} 

//编译器推倒的
//void Print(double x)
//{
//	cout << x << " ";
//	Print();
//}
//
//void Print(const char* x, double z)
//{
//	cout << x << " ";
//	Print(z);
//}
//
//void Print(int x, const char* y, double z)
//{
//	cout << x << " ";
//	Print(y , z);
//}

int main()
{
	ShowList();
	ShowList(1);
	ShowList(1, "xxxxx");
	ShowList(1, "xxxxx", 2.2);
	return 0;
}

///////////////////////////////////////////////////////////

//template <class T>
//int PrintArg(T t)
//{
//	cout << t << " ";
//	return 0;
//}
//
//template <class ...Args>
//void ShowList(Args... args)
//{
//	int arr[] = { PrintArg(args)... };
//	cout << endl;
//}
// 
// //编译推演生成下面的函数
//void ShowList(int x, char y, std::string z)
//{
//	int arr[] = { PrintArg(x),PrintArg(y),PrintArg(z) };
//	cout << endl;
//}
//
//int main()
//{
//	//ShowList(1);
//	//ShowList(1, 'A');
//	ShowList(1, 'A', std::string("sort"));
//
//	return 0;
//}

///////////////////////////////////////////////////////
//emplace_back:能接收左值也可以接收右值
//不支持插入多个值
//总体而言更高效，推荐使用
//可以直接传插入的对象，也可以传构造这个对象的参数包
// 传构造这个对象的参数包高效一些，它会直接构造
// 对于是深拷贝时，如果是右值的话，直接构造 、 构造+移动构造(代价很低) 这两个的效率差不多；如果是左值的话，就更高效了
// 对于浅拷贝的类，没有移动构造的概念，例：日期类 不管左值还是右值都是 构造+拷贝构造，
// 

//int main()
//{
//	list<xlf::string> lt;
//	//左值    
//	xlf::string s1("11111111111111");
//	lt.emplace_back(s1);// 构造+拷贝构造
//
//	//右值
//	lt.emplace_back(move(s1));//构造+移动构造
//
//	//直接把构造string参数包往下传，直接用string参数构造string
//	lt.emplace_back("11111111111111");//构造
//	lt.emplace_back(10, 'x');//构造
//
//	///////////////////////////////////////////////////
//
//	list<pair<xlf::string, int>> lt1;
//	//构造 pair + 拷贝/移动构造pair到list的节点中的data上
//	pair<xlf::string, int> kv("小路飞", 1);
//	lt1.emplace_back(kv);//构造+拷贝构造
//	lt1.emplace_back(move(kv));//构造+拷贝构造
//
//	//直接吧构造pair参数包往下传，直接用pair参数包构造pair
//	lt1.emplace_back("小路飞", 1);//构造
//
//	return 0;
//}





